package command

import (
	"codejy/analysis"
	"codejy/analysis/codeanalysis"
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/utils"
	"flag"
	"fmt"
	"github.com/c-bata/go-prompt"
	"strings"
)

type CodesExceCmd struct {
	codes    bool
	priority int //优先级
}

func init() {
	RegisterCommand(&CodesExceCmd{
		priority: 4,
	})
}

// 绑定
func (m *CodesExceCmd) Bind() {

	flag.BoolVar(&m.codes, "codes", false, m.GetDesc())
}

// 满足条件才执行命令
func (m *CodesExceCmd) Condition() bool {
	return m.codes
}

// 执行命令
func (m *CodesExceCmd) Execute(threadStore *structdef.ThreadStore) {
	Lines()
}

// 获取命令名称
func (m *CodesExceCmd) GetName() string {
	return "codes"
}

// 获取命令描述
func (m *CodesExceCmd) GetDesc() string {
	return `多行代码执行模式(有代码提示) 使用exit退出 ,不支持块代码执行,比如if,for等或者函数定义等,
解决办法可以使用-load导入文件然后调用函数,使用演示: codejy -codes`
}

// 优先级  ,0最低...
func (m *CodesExceCmd) GetPriority() int {
	return m.priority
}

// 是否终止
func (m *CodesExceCmd) IsExit() bool {
	return true
}

var suggest []prompt.Suggest
var p *prompt.Prompt

func completer(in prompt.Document) []prompt.Suggest {
	//根据输入的内容在动态,加载提示,现在先使用预先加载的提示
	return prompt.FilterHasPrefix(suggest, in.GetWordBeforeCursor(), false)
}

var logCode []string
var lineCode string

func executor(in string) {
	defer func() {
		if err := recover(); err != nil {
			//判断报错信息结尾如果是请检查函数是否存在返回值,那么就跳过
			if strings.HasSuffix(fmt.Sprintf("%v", err), "是否存在返回值") {
				return
			}
			fmt.Println("多行命令执行报错:", err)
			store.PrintExecuteCodeRecordLog(store.MainThreadStore, err)
		}
	}()
	//判断输入是history
	if strings.TrimSpace(in) == "history" {
		fmt.Println("历史执行命令:")
		for i := range logCode {
			fmt.Println(i+1, logCode[i])
		}
		return
	}
	//判断命令是否是exit
	if strings.TrimSpace(in) == "exit" {
		fmt.Println("退出多行命令模式")
		utils.Exit()
		return
	}
	//判断输入不是赋值语句,那么就用println给他包装一下
	//去掉所有空格
	in = strings.ReplaceAll(in, " ", "")
	if !analysis.IsVariableDefine(in) && !analysis.AssignmentStatement(store.MainThreadStore, in) {
		in = "println(" + in + ")"
	}
	globalfunc.ExecuteFunc("RunCmdLineCode", store.MainThreadStore, in)
	//绑定实例变量提示
	getVariableInstance(in)
	logCode = append(logCode, in)
}
func Lines() {
	//加载默认类型
	globalfunc.ExecuteFunc("RunCmdLineCode", store.MainThreadStore, "")
	getDefaultFunc() //获取默认函数
	getCodeManual()  //获取代码手册

	////执行代码
	//globalfunc.ExecuteFunc("RunCmdLineCode", store.MainThreadStore, "var a= new(\"List\")")
	////绑定实例变量提示
	//getVariableInstance("vara=new(\"List\")")
	//
	//globalfunc.ExecuteFunc("RunCmdLineCode", store.MainThreadStore, "a.size()")

	p = prompt.New(
		executor,
		completer,
		prompt.OptionTitle("codejy"), //设置标题
		prompt.OptionPrefix("> "),    //前缀文本颜色
		prompt.OptionPrefixTextColor(prompt.Yellow),              //前缀文本颜色
		prompt.OptionPreviewSuggestionTextColor(prompt.Blue),     //预览建议的文本颜色
		prompt.OptionSelectedSuggestionBGColor(prompt.LightGray), //选中建议的背景颜色
		prompt.OptionSelectedDescriptionTextColor(prompt.Black),  //选中建议的描述文本颜色
		prompt.OptionSuggestionTextColor(prompt.Black),           //下拉建议中的文本颜色
		prompt.OptionSuggestionBGColor(prompt.Cyan),              //建议的背景颜色
		prompt.OptionSelectedDescriptionBGColor(prompt.Cyan),     //选中建议的描述背景颜色
		prompt.OptionDescriptionTextColor(prompt.Black),          //下拉建议中的描述文本颜色
		prompt.OptionMaxSuggestion(10),                           //匹配长度
		prompt.OptionScrollbarThumbColor(prompt.DarkGreen),       //滚动条颜色
		prompt.OptionDescriptionBGColor(prompt.Turquoise),        //下拉建议中的描述背景颜色

	)
	p.Run()

}

// 获取所有函数和类型@CodeManual注解
func getCodeManual() {
	var mapPrompt = make(map[string]string)
	//所有函数注解
	annotation := store.GetFileAllFunAnnotation("CodeManual")
	for _, v := range annotation {
		def, _ := v["def"]
		des, _ := v["des"]
		mapPrompt[def] = des
	}
	//所有类型注解
	typeAnnotation := store.GetFileAllTypeAnnotation("CodeManual")
	for _, v := range typeAnnotation {
		def, _ := v["def"]
		des, _ := v["des"]
		mapPrompt[def] = des
	}
	//当前作用域的变量,只装载实例的变量
	variable := store.GetCurrentEnvVariable(store.MainThreadStore)
	for k, v := range variable {
		if v.VarType == codeanalysis.TypeShareInstanceGlobal {
			toString := codeanalysis.VarTypeToString(v.VarType)
			mapPrompt[k] = toString
			//绑定实例变量提示
			instanceAddr, b := store.GetShareTypeVariable(store.MainThreadStore, k, codeanalysis.TypeShareInstanceGlobal)
			if !b {
				return
			}
			prop, _ := store.GetInstanceProp(store.MainThreadStore, instanceAddr.Value)
			typeName, _ := prop["@TYPENAME@"] //获取实例的类型名称
			annotations := store.GetTypeAllPropertiesAnnotation(store.MainThreadStore, typeName.Value, "CodeManual")
			for _, v1 := range annotations {
				def, _ := v1["def"]
				des, _ := v1["des"]
				suggest = append(suggest, prompt.Suggest{Text: k + "." + def, Description: des})
			}
			annotations = store.GetTypeAllMethodsAnnotation(store.MainThreadStore, typeName.Value, "CodeManual")
			for _, v1 := range annotations {
				def, _ := v1["def"]
				des, _ := v1["des"]
				suggest = append(suggest, prompt.Suggest{Text: def, Description: des})
			}
		}
	}
	//装载方法定义提示
	for k, v := range mapPrompt {
		suggest = append(suggest, prompt.Suggest{Text: k, Description: v})
	}
}

// 默认函数提示装载
func getDefaultFunc() {
	suggest = append(suggest, prompt.Suggest{Text: "println(?)", Description: "打印,换行"})
	suggest = append(suggest, prompt.Suggest{Text: "print(?)", Description: "打印,不换行"})
	suggest = append(suggest, prompt.Suggest{Text: "printf(?)", Description: "打印,格式化"})
	suggest = append(suggest, prompt.Suggest{Text: "exit", Description: "退出多行命令模式"})
	suggest = append(suggest, prompt.Suggest{Text: "history", Description: "打印历史正确输入的命令"})
}

// 变量实例提示装载
func getVariableInstance(in string) {
	if analysis.IsVariableDefine(in) || analysis.AssignmentStatement(store.MainThreadStore, in) {
		//获取变量名
		varName := strings.TrimSpace(in[:strings.Index(in, "=")])
		//判断是否是var变量定义
		if strings.HasPrefix(varName, "var") {
			varName = strings.TrimSpace(varName[3:])
		}

		// store.CmdDefaultEnv
		instanceAddr, b := store.GetShareTypeVariable(store.MainThreadStore, varName, codeanalysis.InstanceAddress)
		if !b { //不是实例变量,那么就不用提示了
			return
		}
		//删除原有的提示
		for i := 0; i < len(suggest); i++ {
			if strings.HasPrefix(suggest[i].Text, varName+".") {
				suggest = append(suggest[:i], suggest[i+1:]...)
				i--
			}
		}
		prop, _ := store.GetInstanceProp(store.MainThreadStore, instanceAddr.Value)
		typeName, _ := prop["@TYPENAME@"] //获取实例的类型名称
		annotations := store.GetTypeAllPropertiesAnnotation(store.MainThreadStore, typeName.Value, "CodeManual")
		for _, v := range annotations {
			def, _ := v["def"]
			des, _ := v["des"]
			suggest = append(suggest, prompt.Suggest{Text: varName + "." + def, Description: des})
		}
		annotations = store.GetTypeAllMethodsAnnotation(store.MainThreadStore, typeName.Value, "CodeManual")
		for _, v := range annotations {
			def, _ := v["def"]
			des, _ := v["des"]
			suggest = append(suggest, prompt.Suggest{Text: varName + "." + def, Description: des})
		}
	}
}
